﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using LoggingClient;

namespace ATMCommLib
{
    public abstract class CommHostHandlerThreadBase : ICommHostHandler
    {
        NetworkStream ns;
        ILogger mlogger = null;
        byte[] incoming = new byte[1024];

        bool mRunning = false;

        public void Start(ILogger logger, NetworkStream _ns)
        {
            if (mRunning)
            {
                return;
            }

            ns = _ns;
            mlogger = logger;
            new Thread(new ThreadStart(Run)).Start();
        }

        public abstract void MessageHandler(byte[] content);

        private void Run()
        {
            mRunning = true;

            while (true)
            {
                ProcessMessage();
            }
        }

        private void ProcessMessage()
        {
            try
            {
                if (ns.CanRead)
                {
                    int lengthH = ns.ReadByte();
                    int lengthL = ns.ReadByte();

                    byte[] content = ReadFromStream(lengthH * 256 + lengthL);

                    MessageHandler(content);
                }
            }
            catch (Exception ex)
            {
                mlogger.Error(ex);
            }
        }

        private byte[] ReadFromStream(int msgLength)
        {
            try
            {
                if (msgLength <= 0)
                {
                    return null;
                }

                int newBytes = 0;
                int receivedBytes = 0;

                while (newBytes != -1 && receivedBytes < msgLength)
                {
                    newBytes = ns.Read(incoming, 0, msgLength);
                    receivedBytes = receivedBytes + newBytes;
                }

                if (receivedBytes != msgLength)
                {
                    mlogger.Error("Incomplete Packet is sent to the server!");

                    return null;
                }

                byte[] result = new Byte[msgLength];
                Array.Copy(incoming, 0, result, 0, result.Length);

                return result;
            }
            catch (Exception ex)
            {
                mlogger.Error(ex);
                return null;
            }
        }

        public void WriteLine(byte[] content)
        {
            try
            {
                byte[] LenInfo = CommUtils.ContentTLVLength2Bytes(content);

                ns.Write(LenInfo, 0, 2);
                ns.Write(content, 0, content.Length);
            }
            catch (Exception ex)
            {
                mlogger.Error(ex);
            }
        }

        public void WriteLine(string str)
        {
            try
            {
                byte[] content = CommUtils.GetBytes(str);
                byte[] LenInfo = CommUtils.ContentTLVLength2Bytes(content);

                ns.Write(LenInfo, 0, 2);
                ns.Write(content, 0, content.Length);
            }
            catch (Exception ex)
            {
                mlogger.Error(ex);
            }
        }
    }
}
